/**
 * 采用分离链接法处理散列表code冲突的问题
 * 如果HashCode重复的话
 * 简单总结为: hashCode处存放的不是一个值 而是一个链表或者数组之类的;
 * |- key
 *    |- linkedList
 *      |- ValuePair
 */

import {loseloseHashCode, defaultToString} from "./loseloseHashCode";
import ValuePair from "./ValuePair";
import LinkedList from "../linkedList/LinkedList";

interface HashTableSeparateChainingInterface<TK, TV> {
  item: { [index: number]: LinkedList<ValuePair<TK, TV>> }
  toStrFn: (item: any) => string;
  loseloseHashCode: loseloseHashCode;
  put: (key: TK, value: TV) => void;
  get: (key: TK) => ValuePair<TK, TV> | undefined;
  remove: (key: TK) => ValuePair<TK, TV> | undefined;
}

export default class HashTableSeparateChaining<TK, TV> implements HashTableSeparateChainingInterface<TK, TV> {
  item: { [index: number]: LinkedList<ValuePair<TK, TV>> };
  loseloseHashCode: loseloseHashCode;
  toStrFn: (item: any) => string;

  defaultEquals(a: ValuePair<TK, TV>, b: ValuePair<TK, TV>) {
    return a.key === b.key;
  }

  constructor(toStrFn: (item: any) => string = defaultToString, max: number = 36) {
    this.item = {};
    this.toStrFn = toStrFn;
    this.loseloseHashCode = new loseloseHashCode(toStrFn, max)
  }

  get(key: TK): ValuePair<TK, TV> | undefined {
    let itemElement = this.item[this.loseloseHashCode.getCode(key)];
    if (itemElement) {
      // @ts-ignore
      return itemElement.getValueAt(itemElement.indexOf(new ValuePair<TK, TV>(key, "")))
    }
    return undefined;
  }


  put(key: TK, value: TV): void {
    let el = this.get(key);
    if (el) {
      el.value = value
    } else {
      let itemElement = this.item[this.loseloseHashCode.getCode(key)];
      if (itemElement) {
        // @ts-ignore
        itemElement.push((new ValuePair<TK, TV>(key, value)));
      } else {
        let newLinkedList = new LinkedList<ValuePair<TK, TV>>(this.defaultEquals);
        newLinkedList.push(new ValuePair<TK, TV>(key, value))
        this.item[this.loseloseHashCode.getCode(key)] = newLinkedList;
      }
    }
  }

  remove(key: TK): ValuePair<TK, TV> | undefined {
    let itemElement = this.item[this.loseloseHashCode.getCode(key)];
    if (itemElement) {
      // @ts-ignore
      return itemElement.removeAt(itemElement.indexOf(new ValuePair<TK, TV>(key, "")))
    }
    return undefined;
  }
}


let hashMap = new HashTableSeparateChaining<string, number>()

function print() {
  console.log("#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-#-")
  console.log("java", hashMap.get("java"));
  console.log("javaScript", hashMap.get("javaScript"));
  console.log("javaScript", hashMap.get("javaSrcipt"));
}

print();
hashMap.put("javaScript", 0);
print();

hashMap.put("java", 1);
print();

hashMap.put("javaSrcipt", 2);
print();

hashMap.remove("java")
print();

hashMap.remove("javaSrcipt")
print();
